package cn.dogger.easyboot.nio;

import cn.dogger.easyboot.common.exception.SocketException;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author dogger
 * 2022/11/21 14:42
 */
public class Main {
    public static void main(String[] args)  {
        try {
            ServerSocketChannel serverSocket = ServerSocketChannel.open();
            serverSocket.socket().bind(new InetSocketAddress(8989));
            //设置非阻塞，默认为true；
            serverSocket.configureBlocking(false);
            //创建epoll，多路复用器
            //setSELECTOR(Selector.open());
            Selector selector = Selector.open();
            //ServerSocketChannel注册进selector，并且该selector对客户端accept感兴趣
            serverSocket.register(selector, SelectionKey.OP_ACCEPT);
            while (selector.select() > 0) {
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    //如果是SelectionKey.OP_ACCEPT，就进行客户端连接事件的注册；如果是SelectionKey.OP_READ，就进行读取
                    if (key.isAcceptable()) {
                        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                        //开启非阻塞后此方法不会阻塞，不然会一直卡在这里等待连接
                        //NIO的非阻塞是由系统内部实现的，调用了linux内核的accept函数
                        SocketChannel channel = serverSocketChannel.accept();
                        //设置为非阻塞，否则后面读取到缓冲区时会变阻塞。
                        channel.configureBlocking(false);
                        //客户端连接后，注册成read
                        channel.register(selector, SelectionKey.OP_READ);
                        System.out.println("客户端{}连接"+channel.hashCode());
                    }else if(key.isReadable()) {
                        SocketChannel channel = (SocketChannel) key.channel();
                      //  ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
//                        SocketChannel channel = serverSocketChannel.accept();
//                        channel.configureBlocking(false);
//                        //读取数据后，注册成write
//                        channel.register(selector, SelectionKey.OP_WRITE);
                       // SocketUtils.socketRead(channel);
                        try {
                            //内存缓冲区
                            ByteBuffer allocate = ByteBuffer.allocate(6);
                            //如果channel没有设置非阻塞，则会在这里阻塞
                            int read = channel.read(allocate);
                            //读到数据
                            if (read > 0) {
                                System.out.println("数据接收：" + new String(allocate.array()));
                            } else if (read == -1) {
                                channel.close();
                                System.out.println(channel.hashCode() + "客户端断开连接");
                            }
                        } catch (IOException e) {
                            throw new SocketException(e);
                        }
                    }
                }
            }
        } catch (IOException e) {
            throw new SocketException(e);
        }
    }
}
